//******************************************************** // Horizontal Sundial // NASS Sundial Design Tutorials // Part 2 Sundial Base and Hour Lines // Robert L. Kellogg, Ph.D. // 1 Jan 2020 // // This design is part of the creative commons //******************************************************** /* Tutorial #1 We're going to create the base of a sundial. Three variation are given: a circular sundial and a dial base with 6 or 8 sides (hexagon or octagon). We'll make the sundial base with a slight taper of the sides. This is just a bit of simple esthetics. A goal of making this sundial is to create module procedures such that we can see each step and if we want, experiment with changes to the dial features Tutorial #2 Then we add hour lines. The base of the hour lines is moved off-center to the south by a distance Loffset. We've left enough room around the hour lines that we can add hour numbers in the next tutorial Tutorial #3 We extrude one of three types of gnomons (simple, rounded, and setback) and then place the gnomon onto the dial. We make sure that the foot of the gnomon is placed on the 6am - 6pm line */ echo("Part-3 Adding the Gnomon"); //NASS Tutorial // ---------------------------------------------------- // --------------- Sundial Parameters ---------------- // ---------------------------------------------------- // Note: base units are in mm and angles in degrees shape = "octagon"; // "circular" dial base // "hexagon" dial base // "octagon" dial base type = "setback"; //"simple" gnomon is simple triangle //"rounded" apex tip of gnomon rounded //"setback" base is set back dial_btm = 78; //dial base diam (~3") mm dial_top = 75; //dial base (taper top) mm dial_hght = 3; //dial base height mm lat = 40; //dial latitude deg minHA = 5; //first hour line am hour maxHA = 7; //last hour line pm hour Lwidth = 1; //hour line width mm Lhght = 1; //hour line height mm Llength = dial_top; //hour line length mm Loffset = dial_top/4; //hour line & gnomon offset Dout = .68*dial_top; //outer distance of chapter ring Din = .58*dial_top; //inner distance of chapter ring gbase = 35; //gnomon base for dial of 75mm gwidth = 2; //gnomon width mm gradi = 3; //rounding circle radius mm gsetback = 12; //gnomon base setback mm eps = .01; //epsilon merge mm // ---------------------------------------------------- // ------------ Main Program Starts Here ------------- // ---------------------------------------------------- //basic shape of the sundial if(shape=="circular") { echo("shape",shape); minangle = 3; sundial_base(minangle,turn=0); } if(shape=="octagon") { echo("shape",shape); minangle = 45; sundial_base(minangle,turn=45/2); } if(shape=="hexagon") { echo("shape",shape); minangle = 60; sundial_base(minangle,turn=0); } //add hour lines to the top of the sundial hour_lines(minHA,maxHA,lat); //add gnomon to the sundial if(type == "simple") { echo("type ",type); gnomon_1(lat,gbase,gwidth); } if(type == "rounded"){ echo("type ",type); gnomon_2(lat,gbase,gwidth,gradi); } if(type == "setback"){ echo("type ",type); gnomon_3(lat,gbase,gwidth,gradi,gsetback); } // ---------------------------------------------------- // ----------- Procedure Modules Start Here ----------- // ---------------------------------------------------- module hour_lines(minHA,maxHA,lat){ // first and last hour angle in degrees first = 15*(minHA - 12); last = 15*(maxHA); // loop through the hours for(HA=[first:15:last]){ //theta is the hour line angle theta = atan2(sin(lat)*sin(HA),cos(HA)); translate([0,0,dial_hght]){ intersection(){ //mask the raw hour angle donut_mask(Din,Dout,Lhght); translate([0,-Loffset,0]) // raw hour angle rotate([0,0,theta]) translate([0,Llength/2,Lhght/2]) cube([Lwidth,Llength,Lhght],center=true); } } } } module donut_mask(Din, Dout, Dhght){ //set the cylinder with 180 faces (2 deg segments $fn = 180; //subtract inner cylinder from the outer cylinder difference(){ cylinder(d=Dout,h=Dhght); cylinder(d=Din,h=3*Dhght,center=true); } } module sundial_base(mini,turn){ //create a multi-edge sundial $fa = mini; rotate([0,0,turn]) cylinder($fa,h=dial_hght,d1=dial_btm,d2=dial_top); } module gnomon_1(lat,b,w){ //simple triangular gnomon h = b*tan(lat); //height of gnomon gpoly = [[0,0],[b,0],[0,h]]; //simple triangle // rotate and move gnomon onto the dial translate([w/2,b-Loffset,dial_hght-eps]) rotate([0,0,-90]) rotate([90,0,0]) linear_extrude(height = w, convexity=3) //extrude polygon polygon(gpoly); //make polygon from points } module gnomon_2(lat,b,w,ro){ //rounded tip gnomon h = b*tan(lat); //height of gnomon z = b / cos(lat); //hypotenuse xi = (90 - lat)/2; //half apex angle hp = ro / tan(xi); //tangent distance ho = h - hp; //lower vertical distance zo = z - hp; //lower hypotenuse distance zx = b - zo*cos(lat); //x-tangent pt. on hypotenuse zy = zo*sin(lat); //y-tangent pt. on hypotenuse cx = ro; //x-circle center cy = ho; //y-circle center gpoly = [[0,0],[b,0],[zx,zy],[0,ho]]; //4-point polygon // rotate and move gnomon onto the dial translate([w/2,b-Loffset,dial_hght-eps]) rotate([0,0,-90]) rotate([90,0,0]) union(){ linear_extrude(height=w,convexity=3)//extrude polygon polygon(gpoly); //make polygon from points // add cylinder translate([cx,cy,0]) //move to rounding point cylinder(r = ro,h = w, $fn=180); //180 segments in cylinder } } module gnomon_3(lat,b,w,ro,back){ //setback & rounded tip gnomon h = b*tan(lat); //height of gnomon z = b / cos(lat); //hypoteneus xi = (90 - lat)/2; //half apex angle hp = ro / tan(xi); //tangent distance ho = h - hp; //lower vertical distance zo = z - hp; //lower hypotenuse distance zx = b - zo*cos(lat); //x-tangent pt. on hypotenuse zy = zo*sin(lat); //y-tangent pt. on hypotenuse cx = ro; //x-circle center cy = ho; //y-circle center // now find last tangent point R =sqrt((ro-back)*(ro-back) + (ho*ho)); //circle center to setback beta = acos(ro/R); //apex angle rLR triangle L = R*sin(beta); //setback side length num = (ro-back)/L + ho/ro; den = ro/L + L/ro; //num = ro*(ro-back) + L*ho; //alternate //den = ro*ro + L*L; alpha = acos(num/den); //tangent rotation angle tx = ro*(1-cos(alpha)); //x-tangent pt. of setback ty = ho-ro*sin(alpha); //y-tangent pt. of setback // 4-point poly with setback gpoly =[[back,0],[b,0],[zx,zy],[tx,ty]]; // rotate and move gnomon onto the dial translate([w/2,b-Loffset,dial_hght-eps]) rotate([0,0,-90]) rotate([90,0,0]) union(){ linear_extrude(height=w,convexity=3)//extrude polygon polygon(gpoly); //make polygon from points // add cylinder translate([cx,cy,0]) //move to rounding point cylinder(r = ro,h = w, $fn=180); //180 segments in cylinder } }